package com.zitangkou.user.config;

import com.zitangkou.user.filter.TokenAuthenticationFilter;
import com.zitangkou.user.security.TokenAccessDeniedHandler;
import com.zitangkou.user.security.TokenAuthenticationEntryPoint;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

/**
 * 安全配置类
 *
 * @author Deng Ningning
 * @version 1.0
 * @date 2020/8/31 16:39
 */

@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    private final UserDetailsService userDetailsService;

    private final TokenAuthenticationFilter tokenAuthenticationFilter;

    private final TokenAccessDeniedHandler tokenAccessDeniedHandler;

    private final TokenAuthenticationEntryPoint tokenAuthenticationEntryPoint;

    @Autowired
    public SecurityConfiguration(TokenAuthenticationFilter tokenAuthenticationFilter,
                                 TokenAccessDeniedHandler tokenAccessDeniedHandler,
                                 TokenAuthenticationEntryPoint tokenAuthenticationEntryPoint,
                                 UserDetailsService userDetailsService) {
        this.tokenAuthenticationFilter = tokenAuthenticationFilter;
        this.tokenAccessDeniedHandler = tokenAccessDeniedHandler;
        this.tokenAuthenticationEntryPoint = tokenAuthenticationEntryPoint;
        this.userDetailsService = userDetailsService;
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
                // 基于 token，不需要 session
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                // 拦截异常
                .and().exceptionHandling().accessDeniedHandler(tokenAccessDeniedHandler)
                // 认证入口
                .authenticationEntryPoint(tokenAuthenticationEntryPoint)
                .and()
                .authorizeRequests()
                // 登录、注册、企业等接口放开验证
                .antMatchers(HttpMethod.POST, "/api/v1/users/login/**").permitAll()
                .antMatchers(HttpMethod.POST, "/api/v1/users/register/**").permitAll()
                .antMatchers(HttpMethod.POST, "/api/v1/users/mobile/code").permitAll()
                .antMatchers(HttpMethod.POST, "/api/v1/users/email/code").permitAll()
                .antMatchers(HttpMethod.PUT, "/api/v1/users/forgot/password").permitAll()
                .antMatchers(HttpMethod.GET, "/wx/**").permitAll()
                // 其它请求验证 token
                .anyRequest().authenticated()
                // 验证 token
                .and()
                .addFilterBefore(tokenAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
        // 禁用缓存
        http.headers().cacheControl();
    }
}
